package com.ng.desktop.view.dieta;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;

import com.ng.desktop.model.Categoria;
import com.ng.desktop.persistence.CategoriaPersistence;
import com.ng.desktop.services.NGFactoryBean;
import com.ng.framework.view.desktop.table.NGCustomTable;

public class ComidasPanel extends JPanel {
	
	
	private static final long serialVersionUID = 2525234587192210654L;
	
	private static final Color RED = new Color(250, 128, 114);
	private static final Color YELLOW = new Color(255, 215, 0);
	private static final Color GREEN = new Color(141, 188, 143);
	private static final Color BLUE = new Color(70, 130, 180);
	
	private CategoriaPersistence categoriaPersistence;
	private NGCustomTable tableCategoriasComidas;
	private NGCustomTable tableDistribucion;
	private HashMap<Integer, Double> porciones;
	private Double energia;
	
	public ComidasPanel() {
		this.buildGui();
	}
	
	private void buildGui() {
		this.setLayout(new GridBagLayout());
		
		this.add(new JScrollPane(this.getTableCategoriasComidas(), JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), new GridBagConstraints(0, 0, 1, 1, 1, 0.5, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));
		this.add(new JScrollPane(this.getTableDistribucion(), JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), new GridBagConstraints(0, 1, 1, 1, 1, 0.5, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
	}
	
	private NGCustomTable getTableCategoriasComidas() {
		if(tableCategoriasComidas == null) {
			this.tableCategoriasComidas = new NGCustomTable(new String[] {"Categoría", "Energía", "Max. Porciones", "Porciones", "Energía", "Porciones", "Energía", "Porciones", "Energia", "Porciones", "Energía", "Porciones", "Energía", "Porciones", "Energía", "Total" });
			
			List<Categoria> categorias = this.getCategoriaPersistence().getAll();
			Collections.sort(categorias, new Comparator<Categoria>() {

				@Override
				public int compare(Categoria o1, Categoria o2) {
					return o1.getNombre().compareTo(o2.getNombre());
				}
			});
			
			for(Categoria categoria : categorias) {
				tableCategoriasComidas.addRow(new Object[] { categoria, categoria.getEnergia(), 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d} );
				int lastRow = tableCategoriasComidas.getRowCount() - 1;
				tableCategoriasComidas.setCellEditable(lastRow, 3, true);
				tableCategoriasComidas.setCellForeground(lastRow, 3, BLUE);
				tableCategoriasComidas.setCellEditable(lastRow, 5, true);
				tableCategoriasComidas.setCellForeground(lastRow, 5, BLUE);
				tableCategoriasComidas.setCellEditable(lastRow, 7, true);
				tableCategoriasComidas.setCellForeground(lastRow, 7, BLUE);
				tableCategoriasComidas.setCellEditable(lastRow, 9, true);
				tableCategoriasComidas.setCellForeground(lastRow, 9, BLUE);
				tableCategoriasComidas.setCellEditable(lastRow, 11, true);
				tableCategoriasComidas.setCellForeground(lastRow, 11, BLUE);
				tableCategoriasComidas.setCellEditable(lastRow, 13, true);
				tableCategoriasComidas.setCellForeground(lastRow, 13, BLUE);
			}
			
			tableCategoriasComidas.addRow(new Object[] { "Total", null, null, null, 0d, null, 0d, null, 0d, null, 0d, null, 0d, null, 0d, null, 0d} );
			tableCategoriasComidas.combine(tableCategoriasComidas.getRowCount() - 1, 0, 1, 4);
			tableCategoriasComidas.setCellAlignment(tableCategoriasComidas.getRowCount() - 1, 0, SwingConstants.RIGHT);
			
			tableCategoriasComidas.setNumericColumn(3, Double.class);
			tableCategoriasComidas.setNumericColumn(5, Double.class);
			tableCategoriasComidas.setNumericColumn(7, Double.class);
			tableCategoriasComidas.setNumericColumn(9, Double.class);
			tableCategoriasComidas.setNumericColumn(11, Double.class);
			tableCategoriasComidas.setNumericColumn(13, Double.class);
			
			tableCategoriasComidas.setColumnGroup("Desayuno", 3, 4);
			tableCategoriasComidas.setColumnGroup("Almuerzo", 5, 6);
			tableCategoriasComidas.setColumnGroup("Cena", 7, 8);
			tableCategoriasComidas.setColumnGroup("Refacción 1", 9, 10);
			tableCategoriasComidas.setColumnGroup("Refacción 2", 11, 12);
			tableCategoriasComidas.setColumnGroup("Refacción 3", 13, 14);
			
			tableCategoriasComidas.setAutoResizeMode(NGCustomTable.AUTO_RESIZE_OFF);
			tableCategoriasComidas.getColumnModel().getColumn(0).setPreferredWidth(110);
			tableCategoriasComidas.getColumnModel().getColumn(2).setPreferredWidth(100);
			
			tableCategoriasComidas.getModel().addTableModelListener(new TableModelListener() {
				
				@Override
				public void tableChanged(TableModelEvent e) {
					if((e.getColumn() == 3 || e.getColumn() == 5 || e.getColumn() == 7 || e.getColumn() == 9 || e.getColumn() == 11 || e.getColumn() == 13) 
							&& e.getFirstRow() < ComidasPanel.this.getTableCategoriasComidas().getRowCount() - 1) {
						ComidasPanel.this.updateTable();
					}
				}
			});
		}
		
		return tableCategoriasComidas;
	}
	
	public void updateTable() {
		Double totalEnergiaDesayuno = 0d;
		Double totalEnergiaAlmuerzo = 0d;
		Double totalEnergiaCena = 0d;
		Double totalEnergiaRefaccion1 = 0d;
		Double totalEnergiaRefaccion2 = 0d;
		Double totalEnergiaRefaccion3 = 0d;
		
		for(int i = 0; i < this.getTableCategoriasComidas().getRowCount() - 1; i++) {
			Double maxPorciones = porciones.get(i);
			this.getTableCategoriasComidas().setValueAt(maxPorciones, i, 2);
			
			Double energiaCategoria = (Double)this.getTableCategoriasComidas().getValueAt(i, 1);
			Double totalPorciones = 0d;
			for(int j = 4; j <= 14 ; j = j + 2) {
				Double porciones = (Double)this.getTableCategoriasComidas().getValueAt(i, j - 1);
				totalPorciones += porciones;
				
				Double energiaPorciones = energiaCategoria * porciones;
				this.getTableCategoriasComidas().setValueAt(energiaPorciones, i, j);
				
				switch (j) {
				case 4:
					totalEnergiaDesayuno += energiaPorciones;
					break;
				case 6:
					totalEnergiaAlmuerzo += energiaPorciones;
					break;
				case 8:
					totalEnergiaCena += energiaPorciones;
					break;
				case 10:
					totalEnergiaRefaccion1 += energiaPorciones;
					break;
				case 12:
					totalEnergiaRefaccion2 += energiaPorciones;
					break;
				case 14:
					totalEnergiaRefaccion3 += energiaPorciones;
					break;
				}
			}
			
			int lastRow = this.getTableCategoriasComidas().getRowCount() - 1;
			this.getTableCategoriasComidas().setValueAt(totalEnergiaDesayuno, lastRow, 4);
			this.getTableCategoriasComidas().setValueAt(totalEnergiaAlmuerzo, lastRow, 6);
			this.getTableCategoriasComidas().setValueAt(totalEnergiaCena, lastRow, 8);
			this.getTableCategoriasComidas().setValueAt(totalEnergiaRefaccion1, lastRow, 10);
			this.getTableCategoriasComidas().setValueAt(totalEnergiaRefaccion2, lastRow, 12);
			this.getTableCategoriasComidas().setValueAt(totalEnergiaRefaccion3, lastRow, 14);
			
			
			this.getTableCategoriasComidas().setValueAt(totalPorciones, i, 15);
			
			Color background;
			if(totalPorciones > maxPorciones) {
				background = RED;
			} else if(totalPorciones < maxPorciones) {
				background = YELLOW;
			} else {
				background = GREEN;
			}
			
			for(int j = 0; j < this.getTableCategoriasComidas().getColumnCount(); j++) {
				this.getTableCategoriasComidas().setCellBackground(i, j, background);
			}
		}
		
		this.getTableCategoriasComidas().repaint();
		
		this.updateTableDistribucion();
	}
	
	private CategoriaPersistence getCategoriaPersistence() {
		if(categoriaPersistence == null) {
			this.categoriaPersistence = (CategoriaPersistence) NGFactoryBean.getInstance().getBean("categoriaPersistence");
		}
		
		return categoriaPersistence;
	}
	
	private NGCustomTable getTableDistribucion() {
		if(tableDistribucion == null) {
			this.tableDistribucion = new NGCustomTable(new String[] { "Comida", "Proporción", "Calorías", "Proporcion Real", "Calorías Real" });
			
			tableDistribucion.addRow(new Object[] { "Desayuno", 0d, 0d, 0d, 0d });
			tableDistribucion.addRow(new Object[] { "Almuerzo", 0d, 0d, 0d, 0d });
			tableDistribucion.addRow(new Object[] { "Cena", 0d, 0d, 0d, 0d });
			tableDistribucion.addRow(new Object[] { "Refacción 1", 0d, 0d, 0d, 0d });
			tableDistribucion.addRow(new Object[] { "Refacción 2", 0d, 0d, 0d, 0d });
			tableDistribucion.addRow(new Object[] { "Refacción 3", 0d, 0d, 0d, 0d });
			tableDistribucion.addRow(new Object[] { "Total", 0d, 0d, 0d, 0d });
			
			for(int i = 0; i < tableDistribucion.getRowCount(); i++) {
				tableDistribucion.setCellEditable(i, 1, true);
				tableDistribucion.setCellForeground(i, 1, BLUE);
			}
			tableDistribucion.setNumericColumn(1, Double.class);
			
			tableDistribucion.getModel().addTableModelListener(new TableModelListener() {
				
				@Override
				public void tableChanged(TableModelEvent e) {
					if(e.getColumn() == 1 && e.getFirstRow() < ComidasPanel.this.getTableDistribucion().getRowCount() - 1) {
						ComidasPanel.this.updateTableDistribucion();
					}
				}
			});

		}
		
		return tableDistribucion;
	}
	
	private void updateTableDistribucion() {
		Double totalProporcion = 0d;
		Double totalCalorias = 0d;
		Double totalProporcionReal = 0d;
		Double totalCaloriasReal = 0d;

		int column = 4;
		for(int i = 0; i < this.getTableDistribucion().getRowCount() - 1; i++) {
			Double proporcion = (Double)this.getTableDistribucion().getValueAt(i, 1);
			totalProporcion += proporcion;
			
			Double calorias = energia * proporcion;
			this.getTableDistribucion().setValueAt(calorias, i, 2);
			totalCalorias += calorias;
			
			Double caloriasReal = (Double)this.getTableCategoriasComidas().getValueAt(this.getTableCategoriasComidas().getRowCount() - 1, column);
			this.getTableDistribucion().setValueAt(caloriasReal, i, 4);
			totalCaloriasReal += caloriasReal;
			
			Double proporcionReal = caloriasReal / energia;
			this.getTableDistribucion().setValueAt(proporcionReal, i, 3);
			totalProporcionReal += proporcionReal;
			
			Color background;
			if(calorias.equals(caloriasReal)) {
				background = GREEN;
			} else {
				background = RED;
			}
			
			for(int j = 0; j < this.getTableDistribucion().getColumnCount(); j++) {
				this.getTableDistribucion().setCellBackground(i, j, background);
			}
			
			column += 2;
		}
		
		this.getTableDistribucion().repaint();
		
		int lastRow = this.getTableDistribucion().getRowCount() - 1;
		this.getTableDistribucion().setValueAt(totalProporcion, lastRow, 1);
		this.getTableDistribucion().setValueAt(totalCalorias, lastRow, 2);
		this.getTableDistribucion().setValueAt(totalProporcionReal, lastRow, 3);
		this.getTableDistribucion().setValueAt(totalCaloriasReal, lastRow, 4);
	}
	
	public void setPorciones(HashMap<Integer, Double> porciones) {
		this.porciones = porciones;
	}

	public void setEnergia(Double energia) {
		this.energia = energia;
	}
	
	public HashMap<Comida, HashMap<Long, Double>> getPorcionesComida() {
		HashMap<Comida, HashMap<Long, Double>> porcionesComida = new HashMap<Comida, HashMap<Long,Double>>();
		
		porcionesComida.put(Comida.DESAYUNO, new HashMap<Long, Double>());
		porcionesComida.put(Comida.ALMUERZO, new HashMap<Long, Double>());
		porcionesComida.put(Comida.CENA, new HashMap<Long, Double>());
		porcionesComida.put(Comida.REFACCION1, new HashMap<Long, Double>());
		porcionesComida.put(Comida.REFACCION2, new HashMap<Long, Double>());
		porcionesComida.put(Comida.REFACCION3, new HashMap<Long, Double>());
		
		for(int i = 0; i < this.getTableCategoriasComidas().getRowCount() - 1; i++) {
			Categoria categoria = (Categoria)this.getTableCategoriasComidas().getValueAt(i, 0);
			
			porcionesComida.get(Comida.DESAYUNO).put(categoria.getId(), (Double)this.getTableCategoriasComidas().getValueAt(i, 3));
			porcionesComida.get(Comida.ALMUERZO).put(categoria.getId(), (Double)this.getTableCategoriasComidas().getValueAt(i, 5));
			porcionesComida.get(Comida.CENA).put(categoria.getId(), (Double)this.getTableCategoriasComidas().getValueAt(i, 7));
			porcionesComida.get(Comida.REFACCION1).put(categoria.getId(), (Double)this.getTableCategoriasComidas().getValueAt(i, 9));
			porcionesComida.get(Comida.REFACCION2).put(categoria.getId(), (Double)this.getTableCategoriasComidas().getValueAt(i, 11));
			porcionesComida.get(Comida.REFACCION2).put(categoria.getId(), (Double)this.getTableCategoriasComidas().getValueAt(i, 13));
		}
		
		return porcionesComida;
	}
}
